/**
 * 在 TypeScript 3.7 版本专门引入了 asserts 关键字来进行 断言场景 下的 类型守卫
 * 
 * 断言守卫 和 类型守卫 最大的不同点在于，
 * 在判断条件不通过时，断言守卫 需要抛出一个错误，类型守卫 只需要剔除掉预期的类型。 
*/

/**
 * 下面这段代码在运行时会抛出一个错误，因为 assert 接收到的表达式执行结果为 false。
 * 
 * 这其实也类似类型守卫的场景：
 * 如果断言不成立，比如在这里意味着 值的类型 不为 number，那么在断言下方的代码就执行不到（相当于 Dead Code）。
 * 如果断言通过了，不管最开始是什么类型，断言后的代码中就一定是符合断言的类型，比如在这里就是 number。
 * 
 * 对于 assert(typeof name === 'number'); 这么一个断言，
 * 如果函数成功返回，就说明其后续的代码中 condition 均成立，
 * 也就是 name 神奇地变成了一个 number 类型。
 * 
 * 这也意味着，将 condition 这一逻辑层面的代码，作为了 类型层面 的 判断依据，
 * 相当于在 返回值类型 中使用一个 逻辑表达式 进行了 类型标注。
 * 
*/

let name: any = 'hanxuming';
function assert(condition: any, msg?: string): asserts condition {
    if (!condition) {
        throw new Error(msg);
    }
}
assert(typeof name === 'number');
// number 类型
name.toFixed();

/**
 * 这里的 condition 甚至还可以结合使用 is 关键字来提供进一步的类型守卫能力
 * 
 * 在这种情况下，无需再为断言守卫传入一个表达式，
 * 而是可以将这个 判断用的表达式 放进 断言守卫的内部，来获得更独立地代码逻辑。
 * */
let nameA: any = 'hanxuming';
function assertIsNumber(val: any): asserts val is number {
    if (typeof val !== 'number') {
        throw new Error('Not a number!');
    }
}
assertIsNumber(nameA);
// number 类型！
nameA.toFixed();

//export {}：解决“无法重新声明块范围变量”错误提示问题
export { }